﻿
Imports System.Net.Sockets
Imports System.Net
Imports System.Text
Imports System.Threading

Public Class FrmServerAsync
    Private WithEvents mTCPServer As TCPServerAsync = Nothing
    ''' <summary>
    ''' 服务是否已启动
    ''' </summary>
    Private mListen As Boolean

    ''' <summary>
    ''' 软件字符编码集
    ''' </summary>
    ''' <remarks></remarks>
    Private EnCode As Encoding = Encoding.UTF8




    Private Sub FrmServer_FormClosed(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed
        If mListen Then
            '停止监听
            Call CloseClient()
            SetListenState(Not mListen)
        End If
    End Sub



    Private Sub FrmServer_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        '设置默认端口
        txtLocalPort.Text = 9687

        '获取本地网卡列表
        cmbLocalNetAddr.Items.Clear()
        Try
            '获取本地监听信息
            Dim ipHostInfo As IPHostEntry '获取本机IP地址
            TxtDebug.Text += "本机名称：" + Dns.GetHostName() + vbNewLine
            ipHostInfo = Dns.GetHostEntry(Dns.GetHostName())
            For Each oIP As IPAddress In ipHostInfo.AddressList
                Dim sIPInfo As String
                Dim sType As String
                If oIP.IsIPv6LinkLocal Then
                    sType = "IPV6 地址"
                Else
                    sType = "IPV4 地址"
                End If
                sIPInfo = String.Format("IP：{0},协议类型：{1}{2}", oIP.ToString(), sType, vbNewLine)
                cmbLocalNetAddr.Items.Add(New IPDetial(oIP))
                TxtDebug.Text += sIPInfo
            Next

        Catch ex As Exception
            TxtDebug.Text += $"获取本机IP地址表时发生错误！
{ex.ToString }"
            'Return
        End Try

        '设置初始状态
        SetListenState(False)
    End Sub


#Region "开始服务"
    Private Sub ButListener_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButListener.Click

        If Not mListen Then
            StartServer()

        Else
            '停止监听
            Call CloseClient()
        End If

        SetListenState(mListen)
    End Sub

    Private Sub StartServer()
        Dim lListenerPort As Long
        '开始监听

        If Not Long.TryParse(txtLocalPort.Text, lListenerPort) Then
            MsgBox("请输入正确的监听端口号！", 64, "提示")
            Return
        End If

        Dim ipdtl As IPDetial = TryCast(cmbLocalNetAddr.SelectedItem, IPDetial)
        Dim localEndPoint As IPEndPoint
        If ipdtl Is Nothing Then
            localEndPoint = New IPEndPoint(IPAddress.Any, lListenerPort) '创建一个绑定点
        Else
            Dim ipAddr As IPAddress = ipdtl.Addr

            localEndPoint = New IPEndPoint(ipAddr, lListenerPort) '创建一个绑定点
        End If


        '创建监听器
        mTCPServer = New TCPServerAsync(100000)
        Try
            '将监听器绑定到本地IP的指定端口上

            mTCPServer.Start(localEndPoint) '开始监听
            mListen = True

        Catch ex As Exception
            mTCPServer = Nothing
            AddLog("开始监听失败，监听端口:" & localEndPoint.ToString & vbNewLine & ex.Message)
        End Try
    End Sub

    ''' <summary>
    ''' 设置监听状态
    ''' </summary>
    ''' <param name="bListen"></param>
    ''' <remarks></remarks>
    Private Sub SetListenState(ByVal bListen As Boolean)
        txtLocalPort.ReadOnly = bListen
        cmbLocalNetAddr.Enabled = Not bListen
        If bListen Then
            ButListener.Text = "停止监听"
        Else
            ButListener.Text = "开始监听"
        End If
        mListen = bListen
    End Sub
#End Region

#Region "关闭服务"
    ''' <summary>
    ''' 关闭监听和客户端连接
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub CloseClient()
        '关闭监听
        Try
            mTCPServer.Shutdown()
            mListen = False
        Catch ex As Exception
        End Try



    End Sub
#End Region

    Private Sub TmrStatus_Tick(sender As Object, e As EventArgs) Handles TmrStatus.Tick
        If mListen Then
            TxtClientCount.Text = mTCPServer.ClientCount
            TxtReadByteCount.Text = mTCPServer.TotalBytesRead
        Else
            TxtClientCount.Text = "0"
            TxtReadByteCount.Text = "0"
        End If
    End Sub


#Region "日志"

    ''' <summary>
    ''' 设置输出窗口文本
    ''' </summary>
    ''' <param name="text"></param>
    ''' <remarks></remarks>
    Private Sub AddLog(ByVal [text] As String)
        If (Not chkShowLog.Checked) Then Return

        If Me.TxtDebug.InvokeRequired Then
            Dim d As New Action(Of String)(AddressOf AddLog)
            Me.Invoke(d, New Object() {[text]})
        Else
            Me.TxtDebug.Text = Format(Date.Now, "HH:mm:ss") & "--" & [text] & vbNewLine & TxtDebug.Text
            If TxtDebug.Text.Length > 20000 Then
                Me.TxtDebug.Text = Me.TxtDebug.Text.Substring(0, 13000)
            End If
        End If

    End Sub

    ''' <summary>
    ''' 输出接入的客户端信息
    ''' </summary>
    ''' <param name="oClient"></param>
    ''' <remarks></remarks>
    Private Sub DebugClient(ByRef oClient As SocketInfo)
        Dim sText As String

        sText = "有客户端接入：IP：" & oClient.toString
        AddLog(sText)
    End Sub

    ''' <summary>
    ''' 输出客户返回的数据
    ''' </summary>
    ''' <param name="sText"></param>
    ''' <remarks></remarks>
    Private Sub DebugClientRead(ByRef oClient As Socket, ByVal lByteCount As Integer, ByVal sText As String)
        Dim oIP As IPEndPoint
        Dim sValue As String = "客户端：%1:%2,接收字节：%3；接收数据："

        Try
            oIP = oClient.RemoteEndPoint
            sValue = ReplaceEx(sValue, {oIP.Address.ToString, oIP.Port, lByteCount})
            sValue = sValue & sText

            AddLog(sValue)
        Catch ex As Exception

        End Try

    End Sub

    ''' <summary>
    ''' 输出发送至客户端的内容
    ''' </summary>
    ''' <param name="oClient"></param>
    ''' <param name="sText"></param>
    ''' <param name="bytesSent"></param>
    ''' <remarks></remarks>
    Private Sub DebugClientSend(ByRef oClient As SocketInfo, ByVal sText As String, ByVal bytesSent As Integer)
        Dim sValue As String = "客户端：%1,发送字节：%2，内容：%3"
        sValue = ReplaceEx(sValue, {oClient.toString, bytesSent, sText})
        AddLog(sValue)
    End Sub


    Private Sub butClear_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles butClear.Click
        TxtDebug.Text = String.Empty
    End Sub
#End Region


#Region "发送消息"


    Private Sub ButSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButSend.Click
        If Not mListen Then Return

        If CmbClient.SelectedItem Is Nothing Then
            MsgBox("请选择一个接收数据的客户端！", 64, "提示")
            Return
        End If

        Dim oItem As AsyncClientToken = TryCast(CmbClient.SelectedItem, AsyncClientToken)
        If String.IsNullOrEmpty(oItem.ClientID) Then
            MsgBox("此客户端已不存在！", 64, "提示")
            Return
        End If

        Dim sMsg = TxtSend.Text

        If String.IsNullOrEmpty(sMsg) Then
            MsgBox("请输入需要发送的内容", 64, "提示")
            Return
        End If

        If ChkHex.Checked Then
            If Not CheckIsHex(sMsg) Then
                MsgBox("输入的内容不是十六进制字符串！", 16, "错误")
                Return
            End If
        End If


        'For index = 1 To 100
        If Not mTCPServer.SendMessageToClient(oItem.ClientID, sMsg, EnCode, ChkHex.Checked) Then

            MsgBox("消息发送失败，客户端可能已离线", 64, "提示")
            Return
        End If
        'Next


    End Sub

    Private Sub butReloadClientList_Click(sender As Object, e As EventArgs) Handles butReloadClientList.Click
        '加载客户端列表

        CmbClient.Items.Clear()
        If Not mListen Then Return
        If mTCPServer.ClientCount > 0 Then
            Dim oClients = mTCPServer.GetClientList()
            CmbClient.BeginUpdate()
            CmbClient.Items.AddRange(oClients)
            CmbClient.EndUpdate()
            CmbClient.SelectedIndex = 0
        End If


    End Sub

    Private Sub butGC_Click(sender As Object, e As EventArgs) Handles butGC.Click
        GC.Collect()
    End Sub

    Private Sub butBroadcast_Click(sender As Object, e As EventArgs) Handles butBroadcast.Click
        If Not mListen Then Return
        If mTCPServer.ClientCount = 0 Then
            MsgBox("没有已连接的客户端", 64, "提示")
            Return
        End If

        Dim sMsg = TxtSend.Text

        If String.IsNullOrEmpty(sMsg) Then
            MsgBox("请输入需要发送的内容", 64, "提示")
            Return
        End If

        If ChkHex.Checked Then
            If Not CheckIsHex(sMsg) Then
                MsgBox("输入的内容不是十六进制字符串！", 16, "错误")
                Return
            End If
        End If

        Dim oClients = mTCPServer.GetClientList
        For Each oClient In oClients
            mTCPServer.SendMessageToClient(oClient.ClientID, sMsg, EnCode, ChkHex.Checked)
        Next

    End Sub
#End Region





    Private mAutoCloseClient As Boolean
    Private Sub chkAutoCloseClient_CheckedChanged(sender As Object, e As EventArgs) Handles chkAutoCloseClient.CheckedChanged
        mAutoCloseClient = chkAutoCloseClient.Checked
    End Sub

    Private Sub mTCPServer_ClientAcceptEvent(sender As Object, e As EventArgs) Handles mTCPServer.ClientAcceptEvent
        Dim oClientEvt As ClientEventArgs = TryCast(e, ClientEventArgs)
        Dim oToken = oClientEvt.ClientToken

        AddLog($"有客户端接入：{ oToken.ClientID }   {oToken.Remote}")
    End Sub

    Private Sub mTCPServer_ClientCloseEvent(sender As Object, e As EventArgs) Handles mTCPServer.ClientCloseEvent
        Dim oClientEvt As ClientEventArgs = TryCast(e, ClientEventArgs)
        Dim oToken = oClientEvt.ClientToken

        AddLog($"有客户端断开连接：{ oToken.ClientID }   {oToken.Remote}")
    End Sub

    Private Sub mTCPServer_ClientReceiveEvent(sender As Object, e As EventArgs) Handles mTCPServer.ClientReceiveEvent
        Dim oClientEvt As ClientEventArgs = TryCast(e, ClientEventArgs)
        Dim oToken = oClientEvt.ClientToken
        Dim buf = oToken.Buffer


        If ChkAutoSend.Checked Then
            '自动发回去
            Dim bufSend = mTCPServer.GetNewBuf()
            bufSend.CopyFrom(buf, buf.ReadableBytes)

            mTCPServer.SendBuffer(oToken.ClientID, bufSend)
        End If
        If Not chkShowLog.Checked Then Return



        Dim sMsg As String = String.Empty
        If ChkHex.Checked Then
            sMsg = ByteToHex(buf.Buffer, buf.Offset, buf.ReadableBytes)
        Else
            sMsg = EnCode.GetString(buf.Buffer, buf.Offset, buf.ReadableBytes)
        End If
        AddLog($"接收：{oToken.Remote} :{sMsg}")
    End Sub

    Private Sub mTCPServer_ClientSendOverEvent(sender As Object, e As EventArgs) Handles mTCPServer.ClientSendOverEvent

    End Sub

    Private Sub mTCPServer_ServerCloseEvent(sender As Object, e As EventArgs) Handles mTCPServer.ServerCloseEvent
        Dim oServer As TCPServerAsync = sender

        AddLog("已停止监听：" & oServer.ListenEndPoit.ToString)
    End Sub

    Private Sub mTCPServer_ServerStartEvent(sender As Object, e As EventArgs) Handles mTCPServer.ServerStartEvent
        Dim oServer As TCPServerAsync = sender

        AddLog("已开启监听：" & oServer.ListenEndPoit.ToString)
    End Sub

    Private Sub butCloseAll_Click(sender As Object, e As EventArgs) Handles butCloseAll.Click
        If mTCPServer Is Nothing Then Return
        If mTCPServer.ClientCount > 0 Then
            mTCPServer.CloseAllClient()
        End If
    End Sub
End Class




